package com.warningrc.util.concurrent;

import java.text.MessageFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.log4j.Logger;

import com.warningrc.util.Arrays;

/**
 * 
 * @author <a href="http://weibo.com/weibowarning">王宁</a><br/> email: <a
 *         href="mailto:childe.wangning@gmail.com">childe.wangning@gmail.com</a>
 * @date 2012-3-13
 */
public class MyExecutors {
	private static Logger log = Logger.getLogger(MyExecutors.class);
	private static final Executor executor=getExecutorInstens(null);

	public static Executor getExecutorInstens(String pattern, Object... value) {
		return new Executor(pattern, value);
	}

	/**
	 * 目标方法有返回值时使用该方法调用
	 * 
	 * @param task
	 *            调用代码
	 * @param unit
	 *            超时时间类型
	 * @param timeout
	 *            时间
	 * @return 被调用函数的返回值
	 * @throws TimeoutException
	 *             调用超过指定时间时抛出此异常
	 */
	@SuppressWarnings("unchecked")
	public static <T> T call(Callable<T> task, TimeUnit unit, long timeout)
			throws TimeoutException {
		return executor.call(task, unit, timeout);
	}

	/**
	 * 目标方法无返回值时使用该方法调用
	 * 
	 * @param task
	 *            调用代码
	 * @param unit
	 *            超时时间类型
	 * @param timeout
	 *            时间
	 * @throws TimeoutException
	 *             调用超过指定时间时抛出此异常
	 */
	public static void call(Runnable task, TimeUnit unit, long timeout)
			throws TimeoutException {
		executor.call(task, unit, timeout);
	}

	public static class Executor {
		private static final String DEFAULT_INVOKER_THREAD_NAME = "Executor_Invoker_{0}";
		private int nCount = 0;
		private ExecutorService executor = java.util.concurrent.Executors
				.newCachedThreadPool(new ThreadFactory() {
					public Thread newThread(Runnable task) {
						Thread invokeThread = new Thread(task);
						// 最好起个名字，这在排查分析错误的时候知道该线程是干什么用的
						invokeThread.setName(getInvokerThreadName());
						log.info(invokeThread.getName());
						// 父线程退出时，调用线程也要退出
						invokeThread.setDaemon(true);
						return invokeThread;
					}
				});
		private String invokerThreadName = null;
		private Object[] invokerThreadNameFormatValues = null;

		private Executor(String pattern, Object... value) {
			invokerThreadName = pattern == null ? DEFAULT_INVOKER_THREAD_NAME
					: pattern;
			invokerThreadNameFormatValues = value;
		}

		private String getInvokerThreadName() {
			return MessageFormat.format(invokerThreadName, Arrays.joint(
					new Object[] { nCount++ }, 1,
					invokerThreadNameFormatValues,
					invokerThreadNameFormatValues.length));
		}

		/**
		 * 目标方法有返回值时使用该方法调用
		 * 
		 * @param task
		 *            调用代码
		 * @param unit
		 *            超时时间类型
		 * @param timeout
		 *            时间
		 * @return 被调用函数的返回值
		 * @throws TimeoutException
		 *             调用超过指定时间时抛出此异常
		 */
		@SuppressWarnings("unchecked")
		public <T> T call(Callable<T> task, TimeUnit unit, long timeout)
				throws TimeoutException {
			log.info("call(Callable<?> task, TimeUnit unit, long timeout)");
			Future<?> futureResult = executor.submit(task);
			Object callRet = null;
			try {
				callRet = futureResult.get(timeout, unit);
			} catch (Exception e) {
				if (e instanceof TimeoutException) {
					throw new TimeoutException("invoke timeout!");
				}
				throw new RuntimeException(e);
			}
			return (T) callRet;
		}

		/**
		 * 目标方法无返回值时使用该方法调用
		 * 
		 * @param task
		 *            调用代码
		 * @param unit
		 *            超时时间类型
		 * @param timeout
		 *            时间
		 * @throws TimeoutException
		 *             调用超过指定时间时抛出此异常
		 */
		public void call(Runnable task, TimeUnit unit, long timeout)
				throws TimeoutException {
			log.info("call(Runnable task, TimeUnit unit, long timeout)");
			Future<?> futureResult = executor.submit(task);
			try {
				futureResult.get(timeout, unit);
			} catch (Exception e) {
				if (e instanceof TimeoutException) {
					throw new TimeoutException("invoke timeout!");
				}
				throw new RuntimeException(e);
			}
		}
	}
}
